package com.gitee.fastmybatis.core.ext.util;

import com.gitee.fastmybatis.core.MybatisContext;
import com.gitee.fastmybatis.core.ext.transaction.TransactionTemplateManager;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.Objects;
import java.util.function.Consumer;

/**
 * Mybatis工具类
 *
 * @author thc
 */
public class MybatisUtil {

    /**
     * 获取主数据源SqlSessionFactory
     *
     * @return 返回SqlSessionFactory
     */
    public static SqlSessionFactory getSqlSessionFactory() {
        return MybatisContext.getMainSqlSessionFactory();
    }

    /**
     * 获取Mapper对应的SqlSessionFactory
     *
     * @param mapperClass Mapper class
     * @return 返回SqlSessionFactory
     */
    public static SqlSessionFactory getSqlSessionFactory(Class<?> mapperClass) {
        return MybatisContext.getSqlSessionFactoryByMapperClass(mapperClass);
    }

    /**
     * 获取数据源别名对应的SqlSessionFactory,多数据源配置下可以通过数据源别名获取
     *
     * @param dataSourceAlias 数据源别名
     * @return 返回SqlSessionFactory
     */
    public static SqlSessionFactory getSqlSessionFactory(String dataSourceAlias) {
        return MybatisContext.getSqlSessionFactoryByDataSourceAlias(dataSourceAlias);
    }

    /**
     * 获取主数据源TransactionTemplate
     *
     * @return 返回TransactionTemplate
     */
    public static TransactionTemplate getTransactionTemplate() {
        return TransactionTemplateManager.getTransactionTemplate(MybatisContext.MAIN_DS_ALIAS);
    }

    /**
     * 获取数据源别名对应的TransactionTemplate
     *
     * @param dataSourceAlias 数据源别名
     * @return 返回TransactionTemplate
     */
    public static TransactionTemplate getTransactionTemplate(String dataSourceAlias) {
        return TransactionTemplateManager.getTransactionTemplate(dataSourceAlias);
    }

    /**
     * 运行事务(主数据源)
     *
     * @param action 运行代码
     * @param <T>    返回结果类型
     * @return 返回结果
     * @throws TransactionException 事务异常
     */
    public static <T> T doTransaction(TransactionCallback<T> action) throws TransactionException {
        return doTransaction(getTransactionTemplate(), action);
    }

    private static <T> T doTransaction(TransactionTemplate transactionTemplate, TransactionCallback<T> action) throws TransactionException {
        Objects.requireNonNull(transactionTemplate, "找不到transactionTemplate");
        return transactionTemplate.execute(action);
    }

    /**
     * 运行事务(主数据源),没有返回结果
     *
     * @param action 运行代码
     * @throws TransactionException 事务异常
     */
    public static void doTransactionNoResult(Consumer<TransactionStatus> action) throws TransactionException {
        doTransaction(transactionStatus -> {
            action.accept(transactionStatus);
            return null;
        });
    }

    /**
     * 运行事务
     *
     * @param dbAlias 数据源别名
     * @param action  运行代码
     * @param <T>     返回结果类型
     * @return 返回结果
     * @throws TransactionException 事务异常
     */
    public static <T> T doTransaction(String dbAlias, TransactionCallback<T> action) throws TransactionException {
        TransactionTemplate transactionTemplate = getTransactionTemplate(dbAlias);
        return doTransaction(transactionTemplate, action);
    }

    /**
     * 运行事务,没有返回结果
     *
     * @param dbAlias 数据源别名
     * @param action  运行代码
     * @throws TransactionException 事务异常
     */
    public static void doTransactionNoResult(String dbAlias, Consumer<TransactionStatus> action) throws TransactionException {
        doTransaction(dbAlias, transactionStatus -> {
            action.accept(transactionStatus);
            return null;
        });
    }

}
